package com.wg.core.event;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.wg.core.annotation.EventListener;
import com.wg.core.controller.ControllerMgr;
import com.wg.core.controller.IController;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 事件管理器
 *
 * @author 少爷123
 */
public class EventMgr {
    private static final Log log = LogFactory.get();

    private final Map<Class<? extends Event>, List<EventMethod>> eventHandlers = new ConcurrentHashMap<>();
    private volatile boolean initialized = false;

    private EventMgr() {
    }

    public static EventMgr getInstance() {
        return Singleton.INSTANCE.getManager();
    }

    /**
     * 初始化事件监听器
     *
     * @param packageName 扫描的基础包名（用于日志输出）
     */
    public synchronized void init(String packageName) {
        if (initialized) {
            log.warn("EventMgr already initialized, skipping re-initialization");
            return;
        }

        log.info("Initializing event handlers from package: {}", packageName);
        int handlerCount = 0;

        List<IController> controllers = ControllerMgr.getInstance().getControllers();
        if (controllers == null || controllers.isEmpty()) {
            log.warn("No controllers found during event initialization");
            return;
        }

        for (IController controller : controllers) {
            Method[] methods = ReflectUtil.getPublicMethods(controller.getClass());
            for (Method method : methods) {
                EventListener annotation = method.getAnnotation(EventListener.class);
                if (annotation == null)
                    continue;

                // 验证方法签名
                if (!isValidEventHandler(method)) {
                    log.error("Invalid event handler signature in [Controller: {}, Method: {}]. "
                            + "Expected single parameter of type Event",
                            controller.getClass().getName(), method.getName());
                    continue;
                }

                EventMethod eventMethod = new EventMethod(controller, method, annotation.isAsyn());
                eventHandlers
                        .computeIfAbsent(annotation.value(), k -> Collections.synchronizedList(new ArrayList<>()))
                        .add(eventMethod);

                log.debug("Registered event handler [Event: {}, Controller: {}, Method: {}, Async: {}]",
                        annotation.value().getSimpleName(),
                        controller.getClass().getSimpleName(),
                        method.getName(),
                        annotation.isAsyn());
                handlerCount++;
            }
        }

        log.info("EventMgr initialized. Registered {} handlers for {} event types",
                handlerCount, eventHandlers.size());
        initialized = true;
    }

    /**
     * 发布事件
     *
     * @param event 待发布的事件对象
     */
    public void publish(Event event) {
        if (event == null) {
            log.warn("Attempting to publish null event");
            return;
        }

        Class<? extends Event> eventType = event.getClass();
        List<EventMethod> handlers = eventHandlers.getOrDefault(eventType, Collections.emptyList());

        if (handlers.isEmpty()) {
            log.trace("No handlers found for event type: {}", eventType.getSimpleName());
            return;
        }

        log.debug("Dispatching event [Type: {}, ID: {}] to {} handlers",
                eventType.getSimpleName(), event.getEventId(), handlers.size());

        handlers.parallelStream().forEach(handler -> handler.invoke(event));
    }

    /**
     * 验证方法签名是否符合事件处理器要求
     * - 必须有且仅有一个参数
     * - 参数类型必须是Event或其子类
     */
    private boolean isValidEventHandler(Method method) {
        Class<?>[] paramTypes = method.getParameterTypes();
        return paramTypes.length == 1 && Event.class.isAssignableFrom(paramTypes[0]);
    }

    private enum Singleton {
        INSTANCE;

        private final EventMgr manager;

        Singleton() {
            manager = new EventMgr();
        }

        public EventMgr getManager() {
            return manager;
        }
    }
}